//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <QComboBox>
#include <QLineEdit>
#include "attrevent.h"
#include "primitives.h"
#include "primitivegroup.h"
#include "pttimemarkview.h"
#include "randomdoublewidget.h"
#include "ui_util.h"
#include "viewattributes.h"
//
PTTimeMarkView::PTTimeMarkView(QObject *p_parent)
:
   QObject(p_parent),
   particle_template(0),
   name_edit(new QLineEdit()),
   other_combo(new QComboBox()),
   time_widget(new RandomDoubleWidget())
{
   name_edit->setMaxLength(USER_NAME_MAX);
   other_combo->blockSignals(true);
   other_combo->setEditable(false);
   repopulate_other_combo();
   other_combo->blockSignals(false);
   update_widgets();
   connect(name_edit,SIGNAL(editingFinished()),SLOT(on_name_edit_editingFinished()));
   connect(other_combo,SIGNAL(currentIndexChanged(int)),SLOT(on_other_combo_currentIndexChanged(int)));
   connect(time_widget,SIGNAL(value_changed()),SLOT(on_time_widget_value_changed()));
}
PTTimeMarkView::~PTTimeMarkView()
{
   delete name_edit;
   delete other_combo;
   delete time_widget;
}
//
void PTTimeMarkView::on_name_edit_editingFinished()
{
   if(tm_name.isEmpty())
      return;
   if(!name_edit->isModified())
      return;
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("rename timemark '%2' in particle template '%1'","commands").arg(particle_template->get_name()).arg(tm_name));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),particle_template,new Primitives::PTRenameTimeMark(tm_name,name_edit->text())));
      group->finalize();
   }
   catch(UiError&)
   {
      name_edit->blockSignals(true);
      name_edit->setText(tm_name);
      name_edit->blockSignals(false);
      return;
   }
   group.take();
}
void PTTimeMarkView::on_other_combo_currentIndexChanged(int p_i)
{
   if(tm_name.isEmpty()||p_i<0)
      return;
   model::ParticleTemplate::TimeMark tm=particle_template->time_marks.value(tm_name);
   read_other_combo(p_i,tm);
   {
      QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
      Primitives::SelectPT *prim;
      group->set_description(tr("change 'relative from' in timemark \"%2\" in particle template \"%1\"","commands").arg(particle_template->get_name()).arg(tm_name));
      try
      {
         group->add_exec(prim=new Primitives::SelectPT(get_document(),particle_template,new Primitives::PTChangeTimeMark(tm_name,tm)));
         group->finalize();
      }
      catch(UiError&)
      {
         other_combo->blockSignals(true);
         set_other_combo(get_tm());
         other_combo->blockSignals(false);
         return;
      }
      group.take();
   }
}
void PTTimeMarkView::on_time_widget_value_changed()
{
   model::ParticleTemplate::TimeMark tm=get_tm();
   tm.time=time_widget->get_value();
   {
      QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
      Primitives::SelectPT *prim;
      group->set_description(tr("change time in timemark \"%2\" in particle template \"%1\"","commands").arg(particle_template->get_name()).arg(tm_name));
      try
      {
         group->add_exec(prim=new Primitives::SelectPT(get_document(),particle_template,new Primitives::PTChangeTimeMark(tm_name,tm)));
         group->finalize();
      }
      catch(UiError&)
      {
         time_widget->set_value(get_tm().time);
         return;
      }
      group.take();
   }
}
//
void PTTimeMarkView::handle_set_attr_group()
{
   if(get_attr_group())
   {
      const ViewAttributeType::PTTimeMark *const attr=ViewAttributeType::PTTimeMark::lookup(get_attr_group(),root_object);
      particle_template=attr->get_particle_template();
      tm_name=attr->get_tm_name();
   }
   else
   {
      particle_template=0;
      tm_name="";
   }
   other_combo->blockSignals(true);
   repopulate_other_combo();
   other_combo->blockSignals(false);
   update_widgets();
}
void PTTimeMarkView::handle_attr_event(AttrEvent *p_ae)
{
   if(!get_document())
      return;
   switch(p_ae->get_type())
   {
   case AttrEvent::value_changed:
      {
         AttrValueChanged *avc=static_cast<AttrValueChanged*>(p_ae);
         if(avc->get_name()==root_object)
         {
            const ViewAttributeType::PTTimeMark *const attr=ViewAttributeType::PTTimeMark::lookup(get_attr_group(),root_object);
            particle_template=attr->get_particle_template();
            tm_name=attr->get_tm_name();
            other_combo->blockSignals(true);
            repopulate_other_combo();
            other_combo->blockSignals(false);
            update_widgets();
         }
      }
      break;
   }
}
void PTTimeMarkView::handle_post_primitive(const Primitive &p_prim)
{
   using namespace Primitives;
   //
   if(tm_name.isEmpty())
      return;
   //
   switch(p_prim.type)
   {
   case type_SelectPT:
      {
         const SelectPT &p=static_cast<const SelectPT&>(p_prim);
         if(p.get_pt_id()==particle_template->get_id())
         {
            switch(p.get_delegate().get_type())
            {
            case type_PTRenameTimeMark:
               {
                  const PTRenameTimeMark &d=static_cast<const PTRenameTimeMark&>(p.get_delegate());
                  if(d.get_other_name()==tm_name)
                  {
                     tm_name=d.get_current_name();
                     name_edit->blockSignals(true);
                     name_edit->setText(tm_name);
                     name_edit->blockSignals(false);
                  }
               }
               // fall through
            case type_PTRemTimeMark:
            case type_PTNewTimeMark:
               other_combo->blockSignals(true);
               repopulate_other_combo();
               set_other_combo(get_tm());
               other_combo->blockSignals(false);
               break;
            case type_PTChangeTimeMark:
               {
                  const PTChangeTimeMark &d=static_cast<const PTChangeTimeMark&>(p.get_delegate());
                  if(d.get_name()==tm_name)
                  {
                     other_combo->blockSignals(true);
                     set_other_combo(get_tm());
                     other_combo->blockSignals(false);
                     time_widget->set_value(get_tm().time);
                  }
               }
               break;
            default:
               break;
            }
         }
      }
      break;
   }
}
//
QWidget *PTTimeMarkView::get_name_widget() const
{
   return name_edit;
}
QWidget *PTTimeMarkView::get_other_widget() const
{
   return other_combo;
}
QWidget *PTTimeMarkView::get_time_widget() const
{
   return time_widget;
}
//
void PTTimeMarkView::update_widgets()
{
   name_edit->blockSignals(true);
   other_combo->blockSignals(true);
   name_edit->setText(tm_name);
   if(tm_name.isEmpty())
   {
      name_edit->setDisabled(true);
      other_combo->setDisabled(true);
      other_combo->setCurrentIndex(-1);
      time_widget->set_null_value(true);
   }
   else
   {
      const model::ParticleTemplate::TimeMark &tm=get_tm();
      name_edit->setEnabled(true);
      other_combo->setEnabled(true);
      set_other_combo(tm);
      time_widget->set_value(tm.time);
   }
   name_edit->blockSignals(false);
   other_combo->blockSignals(false);
}
void PTTimeMarkView::repopulate_other_combo()
{
   other_combo->clear();
   if(!tm_name.isEmpty())
   {
      other_combo->addItem(tr("start"));
      other_combo->addItem(tr("end"));
      QList<QString> tm=particle_template->time_marks.keys();
      qSort(tm.begin(),tm.end());
      for(int i=0;i<tm.count();++i)
         other_combo->addItem(tm.at(i),tm.at(i));
   }
}
void PTTimeMarkView::set_other_combo(const model::ParticleTemplate::TimeMark &p_tm)
{
   int i=other_combo->currentIndex();
   switch(p_tm.mode)
   {
   case model::ParticleTemplate::TimeMark::from_start:
      if(i!=0)
         other_combo->setCurrentIndex(0);
      break;
   case model::ParticleTemplate::TimeMark::from_end:
      if(i!=1)
         other_combo->setCurrentIndex(1);
      break;
   case model::ParticleTemplate::TimeMark::from_other:
      {
         int new_i=other_combo->findData(p_tm.other);
         if(new_i!=i)
            other_combo->setCurrentIndex(new_i);
      }
      break;
   default:
      qDebug()<<"PTTimeMarkView: invalid time mark mode "<<p_tm.mode;
      other_combo->setCurrentIndex(-1);
      break;
   }
}
void PTTimeMarkView::read_other_combo(int p_index,model::ParticleTemplate::TimeMark &p_tm)
{
   switch(p_index)
   {
   case 0:
      p_tm.mode=model::ParticleTemplate::TimeMark::from_start;
      p_tm.other="";
      break;
   case 1:
      p_tm.mode=model::ParticleTemplate::TimeMark::from_end;
      p_tm.other="";
      break;
   default:
      p_tm.mode=model::ParticleTemplate::TimeMark::from_other;
      p_tm.other=other_combo->itemData(p_index).toString();
      break;
   }
}
model::ParticleTemplate::TimeMark &PTTimeMarkView::get_tm()
{
   Q_ASSERT(particle_template->time_marks.contains(tm_name));
   return particle_template->time_marks[tm_name];
}
